﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
using System.Windows.Resources;

namespace Sonce.Common
{
    public partial class Loader
    {
        #region Static methods
        /// <summary>
        /// Create an object from xaml string.
        /// </summary>
        /// <param name="xaml">Xaml content as string.</param>
        /// <returns>FrameworkElement object.</returns>
        public static FrameworkElement LoadXaml(string xaml)
        {
            FrameworkElement result = null;
            if (!string.IsNullOrEmpty(xaml))
            {
                try
                {
                    #if SILVERLIGHT
                    result = (FrameworkElement)XamlReader.Load(xaml);
                    #else
                    result = (FrameworkElement)XamlReader.Parse(xaml);
                    #endif
                }
                catch (Exception ex)
                {
                    Logger.Log(ex);
                }
            }
            return result;
        }

        /// <summary>
        /// Load object from the project's resource file.
        /// </summary>
        /// <param name="resourcePath">Relative path to xaml resource.</param>
        /// <returns>FrameworkElement object.</returns>
        public static FrameworkElement LoadResourceXaml(string resourcePath)
        {
            return LoadXaml(LoadResourceString(resourcePath));
        }

        /// <summary>
        /// Load a string from the project's resource file.
        /// </summary>
        /// <param name="resourcePath">Relative path to xaml resource.</param>
        /// <returns>FrameworkElement object.</returns>
        public static string LoadResourceString(string resourcePath)
        {
            string result = null;
            if (!string.IsNullOrEmpty(resourcePath))
            {
                try
                {
                    //Get resource stream, read byte by byte, encode it to string
                    Stream stream = GetResourceStream(AssemblyNames.Resource, resourcePath);
                    if (stream != null)
                    {
                        //TODO: Accelerate loading by using buffers (load array of bytes at single call)
                        int b;
                        List<byte> bytes = new List<byte>();
                        while ((b = stream.ReadByte()) >= 0)
                        {
                            bytes.Add((byte)b);
                        }
                        result = Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count);
                    }
                }
                catch (Exception ex)
                {
                    Logger.Log(ex);
                }
            }
            return result;
        }

        /// <summary>
        /// Find and load style for a control.
        /// </summary>
        /// <param name="control">Control to which style will be applied.</param>
        public static void LoadStyle(Control control)
        {
            try
            {
                //References:
                //http://msdn.microsoft.com/en-us/library/cc296240(VS.95).aspx
                //http://www.silverlightexamples.net/post/How-to-Get-Files-From-Resources-in-Silverlight-20.aspx
                //http://nerddawg.blogspot.com/2008/03/silverlight-2-demystifying-uri.html
                //http://www.codeproject.com/KB/silverlight/CustomControlTechnique.aspx

                int b;
                List<byte> bytes = new List<byte>();
                string name = control.GetType().Name;
                string directory = null;

                #region Get control directory
                switch (name)
                {
                    case "Toolbar":
                    case "ToolbarGroup":
                    case "ToolbarButton":
                        directory = "Toolbar/";
                        break;

                    case "Panelbar":
                    case "PanelbarNode":
                        directory = "Panelbar/";
                        break;

                    case "TreeView":
                    case "TreeNode":
                        directory = "TreeView/";
                        break;

                    default:
                        directory = "Controls/";
                        break;
                }
                #endregion

                string path = "/Sonce.Controls;component/" + directory + name + ".xaml";
                StreamResourceInfo info = Application.GetResourceStream(new Uri(path, UriKind.Relative));
                while ((b = info.Stream.ReadByte()) >= 0)
                {
                    bytes.Add((byte)b);
                }
                string xaml = Encoding.UTF8.GetString(bytes.ToArray(), 0, bytes.Count);

                #if SILVERLIGHT
                object obj = XamlReader.Load(xaml);
                #else
                object obj = XamlReader.Parse(xaml);
                #endif
                if (obj != null && obj is ResourceDictionary)
                {
                    string key = name + "Style";
                    control.Style = (Style)((ResourceDictionary)obj)[key];
                }
            }
            catch (Exception ex)
            {
                Logger.Log(ex);
            }
        }

        /// <summary>
        /// Get a stream from file in resources.
        /// </summary>
        /// <param name="assembly">Assembly name from AssemblyNames enum.</param>
        /// <param name="path">Relative path to the file from resources.</param>
        /// <returns>Stream.</returns>
        public static Stream GetResourceStream(AssemblyNames assembly, string path)
        {
            Stream stream = null;
            try
            {
                string uri = string.Format("/Sonce.{0};component/{1}", assembly.ToString(), path);
                StreamResourceInfo info = Application.GetResourceStream(new Uri(uri, UriKind.Relative));
                stream = info.Stream;
            }
            catch 
            {
            }
            return stream;
        }

        /// <summary>
        /// Get a string from file in resources.
        /// </summary>
        /// <param name="assembly">Assembly name from AssemblyNames enum.</param>
        /// <param name="path">Relative path to the file from resources.</param>
        /// <returns>Returns file content as string.</returns>
        public static string GetResourceString(AssemblyNames assembly, string path)
        {
            string result = null;
            Stream stream = GetResourceStream(assembly, path);
            if (stream != null)
            {
                byte[] buffer = new byte[stream.Length];
                stream.Read(buffer, 0, buffer.Length);
                result = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
            }
            return result;
        }

        /// <summary>
        /// Get Uri that points to the file from resources.
        /// </summary>
        /// <param name="assembly">Assembly name from AssemblyNames enum.</param>
        /// <param name="path">Relative path to the file from resources.</param>
        /// <returns>Uri to the file.</returns>
        public static Uri GetResourceUri(AssemblyNames assembly, string path)
        {
            Uri uri = null;
            try
            {
                uri = new Uri(string.Format("/Sonce.{0};component/{1}", assembly.ToString(), path), UriKind.Relative);
            }
            catch
            {
            }
            return uri;
        }
        #endregion
    }
}
